unit database_states;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
  Buttons, Spin, database_base, itemselectorframeunit, traitlist, fpjson;

type

  { TDatabaseStatesFrame }

  TDatabaseStatesFrame = class(TDatabaseBaseFrame)
    AdditionalDataPanel: TPanel;
    EnemyGetsStateMsgEdit: TEdit;
    NotesGroupBox: TGroupBox;
    NotesMemo: TMemo;
    MainAdditionalDataSplitter: TSplitter;
    StatePersistsMsgEdit: TEdit;
    EnemyGetsStateMsgLabel: TLabel;
    BattleEndCheckBox: TCheckBox;
    RemoveByWalkingCheckBox: TCheckBox;
    ActorGetsStateMsgEdit: TEdit;
    StateEndsMsgEdit: TEdit;
    StatePersistsMsgLabel: TLabel;
    StateEndsMsgLabel: TLabel;
    StatePersistsMsgPlaceholderLabel: TLabel;
    MessagesGroupBox: TGroupBox;
    ActorGetsStatePlaceholderLabel: TLabel;
    EnemyGetsStateMsgPlaceholderLabel: TLabel;
    RemoveByWalkingStepsLabel: TLabel;
    ActorGetsStateMsgLabel: TLabel;
    RemoveByDamagePercentLabel: TLabel;
    RemoveByDamageCheckBox: TCheckBox;
    GeneralSettingsFlowPanel: TFlowPanel;
    GeneralSettingsGroupBox: TGroupBox;
    GeneralSettingsScrollBox: TScrollBox;
    AutoRemovalTimerComboBox: TComboBox;
    AutoRemovalTimerLabel: TLabel;
    DurationLabel: TLabel;
    DurationSeparatorLabel: TLabel;
    DurationMinSpinEdit: TSpinEdit;
    DurationMaxSpinEdit: TSpinEdit;
    RemoveByDamageSpinEdit: TSpinEdit;
    RemoveByWalkingSpinEdit: TSpinEdit;
    StateEndsMsgPlaceholderLabel: TLabel;
    StateTraitListFrame: TTraitListFrame;
    TraitsGroupBox: TGroupBox;
    TraitsNotesSplitter: TSplitter;
    TurnsPanel: TPanel;
    RemovalConditionsGroupBox: TGroupBox;
    IconIdLabel: TLabel;
    IconLabel: TLabel;
    IconPanel: TPanel;
    IconSpeedButton: TSpeedButton;
    MainDataScrollBox: TScrollBox;
    NameEdit: TEdit;
    NameLabel: TLabel;
    NamePanel: TPanel;
    RestrictionEndCheckBox: TCheckBox;
    SvOverlayComboBox: TComboBox;
    SvOverlayLabel: TLabel;
    SvOverlayPanel: TPanel;
    PriorityLabel: TLabel;
    PriorityPanel: TPanel;
    PrioritySpinEdit: TSpinEdit;
    SvMotionComboBox: TComboBox;
    SvMotionLabel: TLabel;
    SvMotionPanel: TPanel;
    SelectorContentSplitter: TSplitter;
    StateSelectorFrame: TItemSelectorFrame;
    RestrictionComboBox: TComboBox;
    RestrictionLabel: TLabel;
    RestrictionPanel: TPanel;
    procedure MsgEditChange(Sender: TObject);
    procedure AutoRemovalTimerComboBoxChange(Sender: TObject);
    procedure BattleEndCheckBoxChange(Sender: TObject);
    procedure DurationMaxSpinEditChange(Sender: TObject);
    procedure DurationMinSpinEditChange(Sender: TObject);
    procedure IconSpeedButtonClick(Sender: TObject);
    procedure Init; override;
    procedure NameEditChange(Sender: TObject);
    procedure NotesMemoChange(Sender: TObject);
    procedure PrioritySpinEditChange(Sender: TObject);
    procedure RemoveByDamageCheckBoxChange(Sender: TObject);
    procedure RemoveByDamageSpinEditChange(Sender: TObject);
    procedure RemoveByWalkingCheckBoxChange(Sender: TObject);
    procedure RemoveByWalkingSpinEditChange(Sender: TObject);
    procedure RestrictionComboBoxChange(Sender: TObject);
    procedure RestrictionEndCheckBoxChange(Sender: TObject);
    procedure SvMotionComboBoxChange(Sender: TObject);
    procedure SvOverlayComboBoxChange(Sender: TObject);
  private
    IsLoading: Boolean;
    SelectedId: Integer;
    function GetSelectedState: TJSONObject;
    procedure LoadGeneralSettings(State: TJSONObject);
    procedure LoadIcon(State: TJSONObject);
    procedure LoadRemovalConditions(State: TJSONObject);
    procedure LoadMessages(State: TJSONObject);
    procedure LoadNotes(State: TJSONObject);
    procedure LoadTraits(State: TJSONObject);
  public
    procedure LoadStateData(Id: Integer);
    procedure UpdateLanguage(Code: String); override;
    destructor Destroy; override;
  end;

resourcestring
  StatesHeader = 'States';

implementation

uses
  globals, comboboxhelper, iconselection;

{$R *.lfm}

{ TDatabaseStatesFrame }

procedure TDatabaseStatesFrame.Init;
begin
  IsLoading := True;

  StateSelectorFrame.SetData(Db.States, @Db.ResizeStates, @LoadStateData);
  StateSelectorFrame.Title := StatesHeader;
  StateSelectorFrame.JsonDataType := 'application/rpgmv-states';
  StateSelectorFrame.CreateElementCallback := @Db.CreateEmptyState;

  FillStateRestrictionComboBox(RestrictionComboBox);
  FillStateSvMotionComboBox(SvMotionComboBox);
  FillStateSvOverlayComboBox(SvOverlayComboBox);
  FillStateAutoRemovalTimingComboBox(AutoRemovalTimerComboBox);

  StateTraitListFrame.SetDatabase(Db);

  {
  SetSameWidthForAllButtons;

  UpdateBackgroud;
  EnemyImageBuffer := TBGRABitmap.Create(EnemiesPaintBox.Width, EnemiesPaintBox.Height);
  EnemyIsMoved := False;
  SelectedMember.IsActive := False;
  TroopBattleEventFrame.SetDatabase(Db);

  SetLength(EnemyImages, Db.Enemies.Count);
  FillEnemiesListBox;
  if EnemiesListBox.Count > 1 then
    EnemiesListBox.ItemIndex := 0;

  }
  LoadStateData(1);
end;

procedure TDatabaseStatesFrame.IconSpeedButtonClick(Sender: TObject);
var
  State: TJSONObject = nil;
  IconIndex: Integer = 0;
  IconIndexJson: TJSONNumber;
begin
  State := GetSelectedState;
  if (State <> nil) and State.Find('iconIndex', IconIndexJson) then
    IconIndex := IconIndexJson.AsInteger;

  if IconSelectionForm.ShowIconSelection(IconIndex) then begin
    State.Integers['iconIndex'] := IconSelectionForm.SelectedIconId;
    LoadIcon(State);
  end;
end;

procedure TDatabaseStatesFrame.BattleEndCheckBoxChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Booleans['removeAtBattleEnd'] := BattleEndCheckBox.Checked;
end;

procedure TDatabaseStatesFrame.DurationMaxSpinEditChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['maxTurns'] := DurationMaxSpinEdit.Value;
end;

procedure TDatabaseStatesFrame.DurationMinSpinEditChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['minTurns'] := DurationMinSpinEdit.Value;
end;

procedure TDatabaseStatesFrame.AutoRemovalTimerComboBoxChange(Sender: TObject);
var
  State: TJSONObject = nil;
  NeedsTurnSelection: Boolean;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['autoRemovalTiming'] := AutoRemovalTimerComboBox.ItemIndex;

  NeedsTurnSelection := AutoRemovalTimerComboBox.ItemIndex > 0;
  DurationMinSpinEdit.Enabled := NeedsTurnSelection;
  DurationMaxSpinEdit.Enabled := NeedsTurnSelection;
end;

procedure TDatabaseStatesFrame.MsgEditChange(Sender: TObject);
var
  PropertyName: String;
  State: TJSONObject = nil;
begin
  PropertyName := 'message' + IntToStr((Sender as TEdit).Tag);

  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Strings[PropertyName] := (Sender as TEdit).Text;
end;

procedure TDatabaseStatesFrame.NameEditChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then begin
    State.Strings['name'] := NameEdit.Text;
    StateSelectorFrame.RefreshSelectedName;
  end;
end;

procedure TDatabaseStatesFrame.NotesMemoChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Strings['note'] := NotesMemo.Text;
end;

procedure TDatabaseStatesFrame.PrioritySpinEditChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['priority'] := PrioritySpinEdit.Value;
end;

procedure TDatabaseStatesFrame.RemoveByDamageCheckBoxChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Booleans['removeByDamage'] := RemoveByDamageCheckBox.Checked;

  RemoveByDamageSpinEdit.Enabled := RemoveByDamageCheckBox.Checked;
end;

procedure TDatabaseStatesFrame.RemoveByDamageSpinEditChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['chanceByDamage'] := RemoveByDamageSpinEdit.Value;
end;

procedure TDatabaseStatesFrame.RemoveByWalkingCheckBoxChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Booleans['removeByWalking'] := RemoveByWalkingCheckBox.Checked;

  RemoveByWalkingSpinEdit.Enabled := RemoveByWalkingCheckBox.Checked;
end;

procedure TDatabaseStatesFrame.RemoveByWalkingSpinEditChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['stepsToRemove'] := RemoveByWalkingSpinEdit.Value;
end;

procedure TDatabaseStatesFrame.RestrictionComboBoxChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['restriction'] := RestrictionComboBox.ItemIndex;
end;

procedure TDatabaseStatesFrame.RestrictionEndCheckBoxChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Booleans['removeByRestriction'] := RestrictionEndCheckBox.Checked;
end;

procedure TDatabaseStatesFrame.SvMotionComboBoxChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['motion'] := SvMotionComboBox.ItemIndex;
end;

procedure TDatabaseStatesFrame.SvOverlayComboBoxChange(Sender: TObject);
var
  State: TJSONObject = nil;
begin
  if not IsLoading then
    State := GetSelectedState;
  if State <> nil then
    State.Integers['overlay'] := SvOverlayComboBox.ItemIndex;
end;

function TDatabaseStatesFrame.GetSelectedState: TJSONObject;
begin
  GetSelectedState := nil;
  if Db.States = nil then
    Exit;
  if (SelectedId >= 1) and (SelectedId < Db.States.Count) then
    GetSelectedState := Db.States.Objects[SelectedId];
end;

procedure TDatabaseStatesFrame.LoadGeneralSettings(State: TJSONObject);
var
  StateName: String = '';
  NameJson: TJSONString;
  Priority: Integer = 0;
  PriorityJson: TJSONNumber;
  Restriction: Integer = 0;
  RestrictionJson: TJSONNumber;
  SvMotion: Integer = 0;
  SvMotionJson: TJSONNumber;
  SvOverlay: Integer = 0;
  SvOverlayJson: TJSONNumber;
begin
  if (State <> nil) and State.Find('name', NameJson) then
    StateName := NameJson.AsString;
  NameEdit.Text := StateName;
  if (State <> nil) and State.Find('priority', PriorityJson) then
    Priority := PriorityJson.AsInteger;
  PrioritySpinEdit.Value := Priority;
  if (State <> nil) and State.Find('restriction', RestrictionJson) then
    Restriction := RestrictionJson.AsInteger;
  RestrictionComboBox.ItemIndex := Restriction;
  if (State <> nil) and State.Find('motion', SvMotionJson) then
    SvMotion := SvMotionJson.AsInteger;
  SvMotionComboBox.ItemIndex := SvMotion;
  if (State <> nil) and State.Find('overlay', SvOverlayJson) then
    SvOverlay := SvOverlayJson.AsInteger;
  SvOverlayComboBox.ItemIndex := SvOverlay;

  LoadIcon(State);
end;

procedure TDatabaseStatesFrame.LoadIcon(State: TJSONObject);
var
  IconId: Integer = 0;
  IconIdJson: TJSONNumber;
  IconBitmap: TBitmap;
begin
  if (State <> nil) and State.Find('iconIndex', IconIdJson) then
    IconId := IconIdJson.AsInteger;

  IconIdLabel.Caption := IntToStr(IconId);
  if IconId <> 0 then begin
    IconBitmap := Game.GetIcon(IconId);
    IconSpeedButton.Glyph.Assign(IconBitmap);
    IconBitmap.Free;
  end else
    IconSpeedButton.Glyph.Clear;
end;

procedure TDatabaseStatesFrame.LoadRemovalConditions(State: TJSONObject);
var
  RemoveAtBattleEnd: Boolean = False;
  RemoveByRestriction: Boolean = False;
  RemoveAtBattleEndJson, RemoveByRestrictionJson: TJSONBoolean;

  AutoRemovalTiming: Integer = 0;
  AutoRemovalTimingJson: TJSONNumber;

  MinTurns: Integer = 0;
  MaxTurns: Integer = 0;
  MinTurnsJson, MaxTurnsJson: TJSONNumber;

  RemoveByDamage: Boolean = False;
  RemoveByDamageJson: TJSONBoolean;
  RemoveByDamageChance: Integer = 0;
  RemoveByDamageChanceJson: TJSONNumber;

  RemoveByWalking: Boolean = False;
  RemoveByWalkingJson: TJSONBoolean;
  RemoveByWalkingSteps: Integer = 0;
  RemoveByWalkingStepsJson: TJSONNumber;
begin
  if (State <> nil) and State.Find('removeAtBattleEnd', RemoveAtBattleEndJson) then
    RemoveAtBattleEnd := RemoveAtBattleEndJson.AsBoolean;
  BattleEndCheckBox.Checked := RemoveAtBattleEnd;

  if (State <> nil) and State.Find('removeByRestriction', RemoveByRestrictionJson) then
    RemoveByRestriction := RemoveByRestrictionJson.AsBoolean;
  RestrictionEndCheckBox.Checked := RemoveByRestriction;

  if (State <> nil) and State.Find('autoRemovalTiming', AutoRemovalTimingJson) then
    AutoRemovalTiming := AutoRemovalTimingJson.AsInteger;
  AutoRemovalTimerComboBox.ItemIndex := AutoRemovalTiming;

  if (State <> nil) and State.Find('maxTurns', MaxTurnsJson) then
    MaxTurns := MaxTurnsJson.AsInteger;
  DurationMaxSpinEdit.Value := MaxTurns;
  if (State <> nil) and State.Find('minTurns', MinTurnsJson) then
    MinTurns := MinTurnsJson.AsInteger;
  DurationMinSpinEdit.Value := MinTurns;

  if (State <> nil) and State.Find('removeByDamage', RemoveByDamageJson) then
    RemoveByDamage := RemoveByDamageJson.AsBoolean;
  RemoveByDamageCheckBox.Checked := RemoveByDamage;
  if (State <> nil) and State.Find('chanceByDamage', RemoveByDamageChanceJson) then
    RemoveByDamageChance := RemoveByDamageChanceJson.AsInteger;
  RemoveByDamageSpinEdit.Value := RemoveByDamageChance;

  if (State <> nil) and State.Find('removeByWalking', RemoveByWalkingJson) then
    RemoveByWalking := RemoveByWalkingJson.AsBoolean;
  RemoveByWalkingCheckBox.Checked := RemoveByWalking;
  if (State <> nil) and State.Find('stepsToRemove', RemoveByWalkingStepsJson) then
    RemoveByWalkingSteps := RemoveByWalkingStepsJson.AsInteger;
  RemoveByWalkingSpinEdit.Value := RemoveByWalkingSteps;
end;

procedure TDatabaseStatesFrame.LoadMessages(State: TJSONObject);
var
  Message1: String = '';
  Message2: String = '';
  Message3: String = '';
  Message4: String = '';
  MessageJson: TJSONString;
begin
  if (State <> nil) and State.Find('message1', MessageJson) then
    Message1 := MessageJson.AsString;
  ActorGetsStateMsgEdit.Text := Message1;

  if (State <> nil) and State.Find('message2', MessageJson) then
    Message2 := MessageJson.AsString;
  EnemyGetsStateMsgEdit.Text := Message2;

  if (State <> nil) and State.Find('message3', MessageJson) then
    Message3 := MessageJson.AsString;
  StatePersistsMsgEdit.Text := Message3;

  if (State <> nil) and State.Find('message4', MessageJson) then
    Message4 := MessageJson.AsString;
  StateEndsMsgEdit.Text := Message4;
end;

procedure TDatabaseStatesFrame.LoadNotes(State: TJSONObject);
var
  Notes: String = '';
  NotesJson: TJSONString;
begin
  if (State <> nil) and State.Find('note', NotesJson) then
    Notes := NotesJson.AsString;
  NotesMemo.Text := Notes;
end;

procedure TDatabaseStatesFrame.LoadTraits(State: TJSONObject);
var
  Traits: TJSONArray;
begin
  if (State <> nil) and State.Find('traits', Traits) then
    StateTraitListFrame.SetTraitList(Traits)
  else
    StateTraitListFrame.SetTraitList(nil);
end;

procedure TDatabaseStatesFrame.LoadStateData(Id: Integer);
var
  State: TJSONObject;
begin
  IsLoading := True;
  SelectedId := Id;

  State := GetSelectedState;
  LoadGeneralSettings(State);
  LoadRemovalConditions(State);
  LoadMessages(State);
  LoadNotes(State);
  LoadTraits(State);

  IsLoading := False;
end;

procedure TDatabaseStatesFrame.UpdateLanguage(Code: String);
begin
  inherited UpdateLanguage(Code);
end;

destructor TDatabaseStatesFrame.Destroy;
begin
  inherited Destroy;
end;

end.

